package cn.tedu.v3_1;

import java.io.*;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.Scanner;

/**
 * 多人聊天室 Version 3.1
 * 优化版本，功能：客户端与服务器端可以双向沟通
 *
 * 问题1：标准IO流置空，线程中使用BufferedRead 无法到达【作用域不够】
 * 流置空的问题更适合在短期，简单场景中使用，不一定保证对象正确释放，
 * 有可能报出null，实际软件开发中使用JavaOOP封装思路替换置空方式
 * 置空流 方式    升级    JavaOOP 封装方式：
 *                              流私有化属性：流，ip，socket..
 *
 * 好处：1.数据保护：本类下可访问，确保其他类无法直接访问
 *      2.易用性和安全性：指控操作--目的：赋值，关闭，紧邻try上！
 *                     私有化属性--->便于修改，流正确的关闭
 */
public class Server {
    private static final int PORT=0202;
    private ServerSocket serverSocket;
    private String ip;
    public Server() {
        try {
            serverSocket = new ServerSocket(PORT);
        } catch (BindException e) {
            System.out.println("请检查端口号，被占用~");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void start() {
        Socket socket = null;
        String ip = null;
        try {
            while (true) {
                System.out.println("等待客户端连接");
                socket = serverSocket.accept();
                new Thread(new ClientHandler(socket)).start();
            }
        } catch (IOException e) {
            System.out.println(ip + "客户端链接断开链接~");
        } finally {
            if (serverSocket != null && !serverSocket.isClosed()) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    System.out.println("服务器关闭失败~~~");
                }
                System.out.println("服务器关闭成功~~Over");
            }
        }
    }

    public static void main(String[] args) {
        Server server = new Server();
        server.start();
    }
    //ClientHandler多线程类：控制客户端发来的通讯消息
    private class ClientHandler implements Runnable {
        private Socket socket;
        private String ip;
        //Server  Client  输入  输出  流  关闭
        private PrintWriter pw;
        private BufferedReader br;

        public ClientHandler(Socket s) {
            this.socket = s;
            ip = socket.getInetAddress().getHostAddress();
            try {
                br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF8"));
                pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF8")), true);
            }
            //catch (UnsupportedEncodingException e) {System.out.println("请检查客户端/服务器端编码集：不一致~");}
            //catch (SocketException e) {System.out.println("客户端链接被重置了~");}
            catch (IOException e) {
                System.out.println("客户端链接断开了~");
            }
        }
        public void run() {
            try {
                new Thread(() -> {
                    try {
                        String message;
                        while ((message = br.readLine()) != null) {//读入客户端
                            System.out.println(ip + "客户端说：" + message);
                            System.out.print("服务器请输入：");
                        }
                    } catch (IOException e) {
                        System.out.println("客户端发来的消息断开了~");
                    }
                }).start();
                Scanner input = new Scanner(System.in);
                while (true) {
                    System.out.println("服务器请输入：");
                    String sme = input.nextLine();
                    pw.println("服务器说：" + sme);
                }
            }finally {
                if (socket != null && !socket.isClosed()) {
                    System.out.println(ip + "客户端退出服务器链接~");
                    try {
                        socket.close();
                    } catch (IOException e) {
                        System.out.println(ip + "客户端退出链接异常~");
                    }
                }
            }

        }
    }
}
















